package cn.sunxiansheng.web.config;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import cn.sunxiansheng.tool.constant.DateParsePatterns;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

/**
 * 自定义日期转换配置：优先级总结
 * <p>
 * 1.	@JsonFormat 注解：最高优先级。
 * 2.	自定义序列化和反序列化器：优先于全局配置，但在检测到 @JsonFormat 时会让位于注解逻辑。
 * 3.	jacksonObjectMapperBuilder.simpleDateFormat()：默认全局配置，优先级最低。
 *
 * @author sunxiansheng
 */
@Configuration
@ConditionalOnClass(com.fasterxml.jackson.databind.ObjectMapper.class)
@AutoConfigureBefore(JacksonAutoConfiguration.class)
public class JacksonConfig {

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer customizer() {
        return jacksonObjectMapperBuilder -> {
            // 设置地区为中国，确保格式符合中文区域习惯
            jacksonObjectMapperBuilder.locale(Locale.CHINA);

            // 设置时区为系统默认时区，避免时区偏差
            jacksonObjectMapperBuilder.timeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));

            // 注册自定义 JavaTimeModule 模块，处理 Java 8 日期时间类型和 Date 类型
            jacksonObjectMapperBuilder.modules(new JavaTimeModule());
        };
    }

    /**
     * JavaTimeModule 是一个自定义的 Jackson 模块，用于序列化和反序列化 Java 8 日期时间类型。
     * •	覆盖默认的 Jackson 序列化和反序列化行为，为 Date 类型字段提供自定义逻辑。
     * •	允许支持多个格式的反序列化，例如通过自定义的 CustomDateDeserializer。
     */
    public static class JavaTimeModule extends SimpleModule {
        public JavaTimeModule() {
            // 添加 LocalDateTime 类型的序列化和反序列化器，确保格式为 "yyyy-MM-dd HH:mm:ss"
            this.addSerializer(LocalDateTime.class,
                    new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            this.addDeserializer(LocalDateTime.class,
                    new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

            // 添加 LocalDate 类型的序列化和反序列化器，确保格式为 "yyyy-MM-dd"
            this.addSerializer(LocalDate.class,
                    new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            this.addDeserializer(LocalDate.class,
                    new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));

            // 添加 LocalTime 类型的序列化和反序列化器，确保格式为 "HH:mm:ss"
            this.addSerializer(LocalTime.class,
                    new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
            this.addDeserializer(LocalTime.class,
                    new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));

            // 添加对 Date 类型的自定义序列化和反序列化，这里会覆盖上面默认的Date序列化器配置
            this.addSerializer(Date.class,
                    new com.fasterxml.jackson.databind.ser.std.DateSerializer(false, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")));
            this.addDeserializer(Date.class, new CustomDateDeserializer());
        }
    }

    /**
     * 自定义的 Date 反序列化器，支持多种格式的日期字符串解析。
     */
    public static class CustomDateDeserializer extends JsonDeserializer<Date> {

        @Override
        public Date deserialize(JsonParser p, com.fasterxml.jackson.databind.DeserializationContext ctxt)
                throws IOException, JsonProcessingException {
            String dateStr = p.getText().trim();
            for (String pattern : DateParsePatterns.PARSE_PATTERNS) {
                try {
                    // 尝试使用每个格式进行解析
                    return new SimpleDateFormat(pattern).parse(dateStr);
                } catch (ParseException e) {
                    // 如果解析失败，继续尝试下一个格式
                }
            }
            // 如果所有格式都不匹配，抛出异常
            throw new IOException("Invalid date format: " + dateStr);
        }
    }
}